using MiniExcelLibs;
using MiniExcelLibs.Attributes;
using MiniExcelLibs.OpenXml;

namespace Digitalmes.Infrastructure.IO;

/// <summary>
/// MiniExcel 导出。
/// </summary>
public sealed class MiniExcelExport : IExcelExport
{
    public void SaveAs<T>(string path, IEnumerable<T> data, ExcelExportOptions? options = null)
    {
        options ??= new();
        var config = BuildConfig(options);

        MiniExcel.SaveAs(path, data, excelType: options.ExcelType, configuration: config);
    }

    public async Task SaveAsAsync<T>(string path, IEnumerable<T> data, ExcelExportOptions? options = null, CancellationToken cancellationToken = default)
    {
        options ??= new();
        var config = BuildConfig(options);

        await MiniExcel.SaveAsAsync(path, data, sheetName: options.SheetName, excelType: options.ExcelType, configuration: config, cancellationToken: cancellationToken);
    }

    public Stream SaveAsStream<T>(IEnumerable<T> data, ExcelExportOptions? options = null)
    {
        options ??= new();
        var config = BuildConfig(options);

        MemoryStream ms = new();
        ms.SaveAs(data, sheetName: options.SheetName, excelType: options.ExcelType, configuration: config);
        ms.Seek(0, SeekOrigin.Begin);

        return ms;
    }

    public async Task<Stream> SaveAsStreamAsync<T>(IEnumerable<T> data, ExcelExportOptions? options = null, CancellationToken cancellationToken = default)
    {
        options ??= new();
        var config = BuildConfig(options);

        MemoryStream ms = new();
        await ms.SaveAsAsync(data, sheetName: options.SheetName, excelType: options.ExcelType, configuration: config, cancellationToken: cancellationToken);
        ms.Seek(0, SeekOrigin.Begin);

        return ms;
    }

    private static OpenXmlConfiguration? BuildConfig(ExcelExportOptions options)
    {
        var config = new OpenXmlConfiguration()
        {
            TableStyles = TableStyles.None,
            AutoFilter = false,
        };

        if (options.ColumnOptions.Length == 0)
        {
            return config;
        }

        List<DynamicExcelColumn> dynamicExcelColumns = [];
        foreach (var columnOptions in options.ColumnOptions)
        {
            DynamicExcelColumn dynamicExcelColumn = new(columnOptions.Key);
            if (!string.IsNullOrEmpty(columnOptions.ColumnName))
            {
                dynamicExcelColumn.Name = columnOptions.ColumnName;
            }
            if (columnOptions.Ignore == true)
            {
                dynamicExcelColumn.Ignore = true;
            }
            if (columnOptions.Index > 0)
            {
                dynamicExcelColumn.Index = columnOptions.Index.Value;
            }
            if (!string.IsNullOrEmpty(columnOptions.Format))
            {
                dynamicExcelColumn.Format = columnOptions.Format;
            }
            if (columnOptions.CustomFormatter != null)
            {
                dynamicExcelColumn.CustomFormatter = columnOptions.CustomFormatter;
            }
            if (columnOptions.Width > 0)
            {
                dynamicExcelColumn.Width = columnOptions.Width.Value;
            }
        }

        config.DynamicColumns = [.. dynamicExcelColumns];
        return config;
    }
}
